package com.amtf.datafile2.cfg.txt;

import java.util.ArrayList;
import java.util.List;

import org.jdom.Attribute;
import org.jdom.DataConversionException;
import org.jdom.Document;
import org.jdom.Element;

import com.amtf.datafile2.cfg.std.StdDefinitionException;
import com.amtf.datafile2.cfg.std.StdDefinitionStore;
import com.amtf.datafile2.cfg.txt.TxtDataTableDefinition.PARSE_MODE;
import com.amtf.datafile2.core.std.StdDataFieldFormat;
import com.amtf.datafile2.core.txt.TxtDataFieldFormatPadLeft;
import com.amtf.datafile2.core.txt.TxtDataFieldPadRight;
import com.amtf.datafile2.core.txt.TxtDataRecord;
import com.amtf.datafile2.core.txt.TxtFTAlphabet;
import com.amtf.datafile2.core.txt.TxtFTAlphabetNumeric;
import com.amtf.datafile2.core.txt.TxtFTAny;
import com.amtf.datafile2.core.txt.TxtFTNumeric;

public class TxtDataTableDefinitionStore extends StdDefinitionStore<TxtDataTableDefinition> {
	public static final TxtDataTableDefinitionStore config = new TxtDataTableDefinitionStore();
	public static final TxtDataTableDefinition UTF8_CSV_NOTITLE = new TxtDataTableDefinition("CSV", "UTF-8", false, false, ',', '"', PARSE_MODE.SOURCE_PRIORITY);
	public static final TxtDataTableDefinition UTF8_TSV_NOTITLE = new TxtDataTableDefinition("TSV", "UTF-8", false, false, '\t', '"', PARSE_MODE.SOURCE_PRIORITY);
	public static final TxtDataTableDefinition UTF8_CSV_WITH_TITLE = new TxtDataTableDefinition("CSV", "UTF-8", true, true, ',', '"', PARSE_MODE.SOURCE_PRIORITY);
	public static final TxtDataTableDefinition UTF8_TSV_WITH_TITLE = new TxtDataTableDefinition("TSV", "UTF-8", true, true, '\t', '"', PARSE_MODE.SOURCE_PRIORITY);

	// @Override
	// protected File[] getDefaultConfigFiles() {
	// return null;
	// }

	public static TxtDataTableDefinition extractConfig(String defineFile) throws StdDefinitionException {
		Document doc = loadDocument(defineFile);
		return config.parse(doc, doc.getRootElement());
	}

	@Override
	public TxtDataTableDefinition parse(Document doc, Element root) throws StdDefinitionException {
		Attribute attrib = null;
		Element recordDef = doc.getRootElement().getChild("record-definition");
		if (recordDef == null) {
			recordDef = doc.getRootElement().getChild("RecordDefinition");
			if (recordDef == null) {
				throw new StdDefinitionException("Record definition format invalid!");
			}
		}

		String name = recordDef.getAttributeValue("name");
		if (name == null || "".equals(name)) {
			name = "default";
			// throw new DefinitionException("Record definition name is empty!");
		}

		TxtDataTableDefinition dataRecDef = new TxtDataTableDefinition(name);

		String encoding = recordDef.getAttributeValue("encoding");
		if (encoding != null && !"".equals(encoding)) {
			dataRecDef.setEncoding(encoding);
		}

		attrib = recordDef.getAttribute("firstRowTitle");
		if (attrib != null) {
			try {
				dataRecDef.setFirstRowTitle(attrib.getBooleanValue());
			} catch (DataConversionException e1) {
				throw new StdDefinitionException("firstRowTitle is empty!");
			}
		}

		attrib = recordDef.getAttribute("titleAsColumnName");
		if (attrib != null) {
			try {
				dataRecDef.setTitleAsColumnName(attrib.getBooleanValue());
			} catch (DataConversionException e1) {
				throw new StdDefinitionException("titleAsColumnName is empty!");
			}
		}

		String delimiter = recordDef.getAttributeValue("columnDelimiter");
		if (delimiter != null && !"".equals(delimiter)) {
			dataRecDef.setFieldDelimiter(delimiter.charAt(0));
		} else {
			delimiter = recordDef.getAttributeValue("fieldDelimiter");
			if (delimiter != null && !"".equals(delimiter)) {
				dataRecDef.setFieldDelimiter(delimiter.charAt(0));
			}
		}

		String smartQuote = recordDef.getAttributeValue("smartQuote");
		if (smartQuote != null) {
			if ("false".equalsIgnoreCase(smartQuote) || "".equals(smartQuote)) {
				dataRecDef.setSmartQuote(' ');
			} else {
				dataRecDef.setSmartQuote(smartQuote.charAt(0));
			}
		}

		String rowTerminator = recordDef.getAttributeValue("rowTerminator");
		if (rowTerminator != null && !"".equals(rowTerminator)) {
			dataRecDef.setRowTerminator(rowTerminator);
		}

		String parseMode = recordDef.getAttributeValue("parseMode");
		if (parseMode != null && !"".equals(parseMode)) {
			dataRecDef.setParseMode(PARSE_MODE.valueOf(parseMode.toUpperCase()));
		}

		String clsName = recordDef.getAttributeValue("dataRecordClass");
		if (clsName != null && !"".equals(clsName)) {
			try {
				dataRecDef.setDataRecordClass((Class<? extends TxtDataRecord>) Class.forName(clsName));
			} catch (ClassNotFoundException e1) {
				throw new StdDefinitionException("Error occured when new instance of DataRecord class! " + e1.getMessage());
			}
		}

		int index = 0;
		List<TxtDataFieldDefinition> fieldDefinition = new ArrayList<TxtDataFieldDefinition>();
		List<Element> es = recordDef.getChildren();
		for (Element e : es) {
			if (e.getName().toLowerCase().contains("column")) {
				index++;

				name = e.getAttributeValue("name");
				if (name == null || name.length() == 0) {
					if (dataRecDef.getParseMode() == PARSE_MODE.SOURCE_PRIORITY) {
						throw new StdDefinitionException("Column name must be define when parseMode is " + PARSE_MODE.SOURCE_PRIORITY.name());
					}

					name = "Column" + index;
				}
				TxtDataFieldDefinition fieldDef = new TxtDataFieldDefinition(name, dataRecDef);

				try {
					fieldDef.setCheckFormat(e.getAttribute("checkFormat").getBooleanValue());
				} catch (Throwable e1) {
					fieldDef.setCheckFormat(false);
				}
				try {
					fieldDef.setAllowEmpty(e.getAttribute("allowEmpty").getBooleanValue());
				} catch (Throwable e1) {
					fieldDef.setAllowEmpty(true);
				}
				int maxLength;
				try {
					maxLength = e.getAttribute("maxLength").getIntValue();
				} catch (Throwable e1) {
					maxLength = -1;
				}
				int minLength;
				try {
					minLength = e.getAttribute("minLength").getIntValue();
				} catch (Throwable e1) {
					minLength = 0;
				}
				try {
					String valueTypeName = e.getAttribute("type").getValue();
					if ("n".equalsIgnoreCase(valueTypeName)) {
						fieldDef.setType(new TxtFTNumeric(minLength, maxLength));
					} else if ("a".equalsIgnoreCase(valueTypeName)) {
						fieldDef.setType(new TxtFTAlphabet(minLength, maxLength));
					} else if ("an".equalsIgnoreCase(valueTypeName) || "na".equalsIgnoreCase(valueTypeName)) {
						fieldDef.setType(new TxtFTAlphabetNumeric(minLength, maxLength));
					} else if ("any".equalsIgnoreCase(valueTypeName)) {
						fieldDef.setType(new TxtFTAny(minLength, maxLength));
					} else {
						fieldDef.setType(new TxtFTAny(minLength, maxLength));
					}
				} catch (Throwable e1) {
					fieldDef.setType(new TxtFTAny(minLength, maxLength));
				}

				try {
					fieldDef.setTrimValue(e.getAttribute("trimValue").getBooleanValue());
				} catch (Throwable e1) {
					fieldDef.setTrimValue(false);
				}

				try {
					Attribute a_wipeSmartQuote = e.getAttribute("wipeSmartQuote");
					if (a_wipeSmartQuote != null && a_wipeSmartQuote.getBooleanValue() == false) {
						fieldDef.setQuote(' ');
					} else {
						fieldDef.setQuote(dataRecDef.getSmartQuote());
					}
				} catch (Throwable e1) {
					fieldDef.setQuote(dataRecDef.getSmartQuote());
				}

				try {
					Attribute atR = e.getAttribute("rightpad");
					Attribute atL = e.getAttribute("leftpad");
					if (atR != null) {
						fieldDef.setFormat(new TxtDataFieldPadRight(maxLength, atR.getValue()));
					} else if (atL != null) {
						fieldDef.setFormat(new TxtDataFieldFormatPadLeft(maxLength, atL.getValue()));
					} else {
						fieldDef.setFormat(new StdDataFieldFormat());
					}
				} catch (Throwable e1) {
					fieldDef.setFormat(new StdDataFieldFormat());
				}

				fieldDefinition.add(fieldDef);
			}
		}

		dataRecDef.addFields(fieldDefinition);

		if (dataRecDef.getParseMode() == PARSE_MODE.SOURCE_PRIORITY) {
			if (fieldDefinition.size() != 0 && dataRecDef.isFirstRowTitle() == false) {
				throw new StdDefinitionException("isFirstRowTitle must be 'true' when parseMode is " + PARSE_MODE.SOURCE_PRIORITY.name());
			}
		}

		this.addConfiguration(dataRecDef);
		return dataRecDef;
	}

	// @Override
	// public DefinitionStore<TxtDataRecordDefinition> loadConfig(String defineFile) throws DefinitionException {
	// DefinitionStore.loadConfig(config, defineFile);
	// return config;
	// }
}
